package redisclient

import (
	"gitee.com/lsy007/redisclient/model"
	"github.com/pquerna/ffjson/ffjson"
)

// ZAdd(key string, scoreMembers ...ScoreMember) (int64,err error)
// ZCard(key string) (int64,err error)
// ZCount(key string, start float64, end float64) (int64,err error)
// ZIncrBy(key string, incr float64, member string) (float64,err error)
// ZInterStore(destination string, opt *ZStore) (int64,err error)
// ZLexCount(key, min, max string) (int64,err error)
// ZRange(key string, start, end int64) ([]string,err error)
// ZRangeByLex(key string, opt *ZRangeByLex) ([]string,err error)
// ZRangeByScore(key string, opt *ZRangeByScore) ([]string,err error)
// ZRank(key string, member string) (int64,err error)
// ZRem(key string, members ...string) (int64,err error)
// ZRemRangeByLex(key, min string, max string) (int64,err error)
// ZRemRangeByRank(key string, start, end int64) (int64,err error)
// ZRemRangeByScore(key string, start float64, end float64) (int64,err error)
// ZRevRange(key string, start, end int64) ([]string,err error)
// ZRevRangeByScore(key string, opt *ZRangeByScore) ([]string,err error)
// ZRevRank(key string, member string) (int64,err error)
// ZScore(key string, member string) (float64,err error)
// ZUnionStore(destination string, opt *ZStore) (int64,err error)
// ZScan(key string, cursor int64, match string, count int64) ([]string, int64,err error)

// ZSet score-member
type ScoreMember struct {
	Score  float64
	Member string
}

// ZStore is used as an arg to ZInterStore and ZUnionStore.
type ZStore struct {
	Keys    []string
	Weights []float64
	// Can be SUM, MIN or MAX.
	Aggregate string
}

// ZRangeByLex is used as an arg to ZRangeByLex
type ZRangeByLex struct {
	Min, Max      string
	Offset, Count int64
}

// ZRangeByScore is used as an arg to ZRangeByScore
type ZRangeByScore struct {
	Min, Max      float64
	Offset, Count int64
}

// 向有序结合添加（更新）一个或多个成员
func (c *RedisClient) ZAdd(key string, scoreMembers ...*ScoreMember) (count int64, err error) {
	scoreMemberSlice := make([]*model.ScoreMember, 0)
	for _, sm := range scoreMembers {
		scoreMemberSlice = append(scoreMemberSlice, &model.ScoreMember{
			Score:  sm.Score,
			Member: sm.Member,
		})
	}
	args := &model.RedisArgsModel{Key: key, ScoreMembers: scoreMemberSlice}
	response, err = c.Request("ZAdd", "ZSet", args)
	return response.Int, err
}

// 获取有序集合的成员的数量
func (c *RedisClient) ZCard(key string) (count int64, err error) {
	args := &model.RedisArgsModel{Key: key}
	response, err = c.Request("ZCard", "ZSet", args)
	return response.Int, err
}

// 计算在有序集合中指定区间分数的成员数
func (c *RedisClient) ZCount(key string, start float64, end float64) (count int64, err error) {
	args := &model.RedisArgsModel{Key: key, StartFloat: start, EndFloat: end}
	response, err = c.Request("ZCount", "ZSet", args)
	return response.Int, err
}

// 有序集合中对指定成员的分数加上增量 increment
func (c *RedisClient) ZIncrBy(key string, incr float64, member string) (score float64, err error) {
	args := &model.RedisArgsModel{Key: key, IncrFloat: incr, Value: member}
	response, err = c.Request("ZIncrBy", "ZSet", args)
	return response.Float, err
}

// 计算给定的一个或多个有序集的交集，并将结果集存储在新的有序集合 key 中
func (c *RedisClient) ZInterStore(destination string, opt *ZStore) (count int64, err error) {
	args := &model.RedisArgsModel{Destination: destination, Keys: opt.Keys, Weights: opt.Weights, Aggregate: opt.Aggregate}
	response, err = c.Request("ZInterStore", "ZSet", args)
	return response.Int, err
}

// 在有序集合中计算指定字典区间内成员数量
func (c *RedisClient) ZLexCount(key, min, max string) (count int64, err error) {
	args := &model.RedisArgsModel{Key: key, StartString: min, EndString: max}
	response, err = c.Request("ZLexCount", "ZSet", args)
	return response.Int, err
}

// 通过索引区间返回有序集合指定区间内的成员
func (c *RedisClient) ZRange(key string, start, end int64) (members []string, err error) {
	args := &model.RedisArgsModel{Key: key, StartInt: start, EndInt: end}
	response, err = c.Request("ZRange", "ZSet", args)
	return response.StringSlice, err
}

// 通过字典区间返回有序集合的成员
func (c *RedisClient) ZRangeByLex(key string, opt *ZRangeByLex) (members []string, err error) {
	args := &model.RedisArgsModel{Key: key, StartString: opt.Min, EndString: opt.Max, Offset: opt.Offset, Count: opt.Count}
	response, err = c.Request("ZRangeByLex", "ZSet", args)
	return response.StringSlice, err
}

// 通过分数返回有序集合指定区间内的成员
func (c *RedisClient) ZRangeByScore(key string, opt *ZRangeByScore) (members []string, err error) {
	args := &model.RedisArgsModel{Key: key, StartFloat: opt.Min, EndFloat: opt.Max, Offset: opt.Offset, Count: opt.Count}
	response, err = c.Request("ZRangeByScore", "ZSet", args)
	return response.StringSlice, err
}

// 返回有序集合中指定成员的索引
func (c *RedisClient) ZRank(key string, member string) (index int64, err error) {
	args := &model.RedisArgsModel{Key: key, Value: member}
	response, err = c.Request("ZRank", "ZSet", args)
	return response.Int, err
}

// 移除有序集合中的一个或多个成员
func (c *RedisClient) ZRem(key string, members ...interface{}) (count int64, err error) {
	var bytes []byte
	if bytes, err = ffjson.Marshal(members); err != nil {
		return
	}
	args := &model.RedisArgsModel{Key: key, Bytes: bytes}
	response, err = c.Request("ZRem", "ZSet", args)
	return response.Int, err
}

// 移除有序集合中给定的字典区间的所有成员
func (c *RedisClient) ZRemRangeByLex(key, min string, max string) (count int64, err error) {
	args := &model.RedisArgsModel{Key: key, StartString: min, EndString: max}
	response, err = c.Request("ZRemRangeByLex", "ZSet", args)
	return response.Int, err
}

// 移除有序集合中给定索引区间的所有成员
func (c *RedisClient) ZRemRangeByRank(key string, start, end int64) (count int64, err error) {
	args := &model.RedisArgsModel{Key: key, StartInt: start, EndInt: end}
	response, err = c.Request("ZRemRangeByRank", "ZSet", args)
	return response.Int, err
}

// 移除有序集合中给定的分数区间的所有成员，包含边界值
func (c *RedisClient) ZRemRangeByScore(key string, start float64, end float64) (count int64, err error) {
	args := &model.RedisArgsModel{Key: key, StartFloat: start, EndFloat: end}
	response, err = c.Request("ZRemRangeByScore", "ZSet", args)
	return response.Int, err
}

// 返回有序集中指定索引区间内的成员，分数从高到低
func (c *RedisClient) ZRevRange(key string, start, end int64) (members []string, err error) {
	args := &model.RedisArgsModel{Key: key, StartInt: start, EndInt: end}
	response, err = c.Request("ZRevRange", "ZSet", args)
	return response.StringSlice, err
}

// 返回有序集中指定分数区间内的成员，分数从高到低排序
func (c *RedisClient) ZRevRangeByScore(key string, opt *ZRangeByScore) (members []string, err error) {
	args := &model.RedisArgsModel{Key: key, StartFloat: opt.Min, EndFloat: opt.Max, Offset: opt.Offset, Count: opt.Count}
	response, err = c.Request("ZRevRangeByScore", "ZSet", args)
	return response.StringSlice, err
}

// 返回有序集合中指定成员的排名，有序集成员按分数值递减(从大到小)排序
func (c *RedisClient) ZRevRank(key string, member string) (rank int64, err error) {
	args := &model.RedisArgsModel{Key: key, Value: member}
	response, err = c.Request("ZRevRank", "ZSet", args)
	return response.Int, err
}

// 返回有序集中，成员的分数值
func (c *RedisClient) ZScore(key string, member string) (score float64, err error) {
	args := &model.RedisArgsModel{Key: key, Value: member}
	response, err = c.Request("ZScore", "ZSet", args)
	return response.Float, err
}

// 计算给定的一个或多个有序集的并集，并存储在新的 key 中
func (c *RedisClient) ZUnionStore(destination string, opt *ZStore) (count int64, err error) {
	args := &model.RedisArgsModel{Destination: destination, Keys: opt.Keys, Weights: opt.Weights, Aggregate: opt.Aggregate}
	response, err = c.Request("ZUnionStore", "ZSet", args)
	return response.Int, err
}

//迭代有序集合中的元素（包括元素成员和元素分值）
func (c *RedisClient) ZScan(key string, cursor int64, match string, count int64) (scoreMember []string, nextCursor int64, err error) {
	args := &model.RedisArgsModel{Key: key, Cursor: cursor, Match: match, Count: count}
	response, err = c.Request("ZScan", "ZSet", args)
	return response.StringSlice, response.Int, err
}
